﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Web.Mvc;
using Mindfor.Web.Data;
using Mindfor.Web.Routing;
using NHibernate;
using NHibernate.Linq;
using Mindfor.Web.Models;

namespace Mindfor.Web.Mvc.Controllers
{
	/// <summary>
	/// Provides functions for log managing.
	/// </summary>
	[CmsAuthorize(CmsRoles.Administrator)]
	public class LogController : CmsPageController
	{
		/// <summary>
		/// Log items per page.
		/// </summary>
		const int ItemsPerPage = 50;

		/// <summary>
		/// Returns page result which renders index view.
		/// </summary>
		/// <param name="page">Current page number.</param>
		/// <param name="startDate">Low bound Date.</param>
		/// <param name="endDate">High bound Date.</param>
		/// <param name="text">Text for search.</param>
		[UrlRoute]
		[UrlRouteDefault("page", 1)]
		[UrlRoute(1, "Page{page}")]
		[UrlRouteConstraint(1, "page", Constraints.IsInt)]
		[ManageLink("Логи", "Система управления")]
		public ActionResult Index(int page, string startDate, string endDate, string text)
		{
			// save params
			int pageIndex = page - 1;
			Session["Log.Page"] = page;
			Session["Log.Qs"] = this.Request.QueryString;

			// get all logs
			IQueryable<Log> logs = Data.Query<Log>();

			// filter by startDate
			DateTime filterStartDate = DateTime.UtcNow;
			if (!string.IsNullOrEmpty(startDate))
			{
				if (!DateTime.TryParse(startDate, out filterStartDate))
					ModelState.AddModelError("StartDate", "Введите корректную дату начала");
				else
					logs = logs.Where(l => l.Date >= filterStartDate.ToUniversalTime());
			}

			// filter by endDate
			DateTime filterEndDate = DateTime.UtcNow;
			if (!string.IsNullOrEmpty(endDate))
			{
				if (!DateTime.TryParse(endDate, out filterEndDate))
					ModelState.AddModelError("EndDate", "Введите корректную дату окончания");
				else
					logs = logs.Where(l => l.Date < filterEndDate.ToUniversalTime());
			}

			// filter by containing text
			if (!string.IsNullOrEmpty(text))
			{
				logs = logs.Where(l => l.ShortText.Contains(text) ||
										l.Description.Contains(text));
			}

			// filter by LogType
			List<byte> types = new List<byte>();
			foreach (string key in this.Request.Params)
			{
				if (key.Length > 0 && key[0] == 'T')
				{
					byte num;
					bool val;
					if (byte.TryParse(key.Substring(1), out num) &&
						bool.TryParse(this.Request[key], out val) && val)
						types.Add(num);
				}
				
			}
			if (types.Count > 0)
				logs = logs.Where(l => types.Contains(l.LogType));
			
			// prepare data
			int itemsCount = logs.Count();
			ViewData["LogType"] = types;
			ViewData["Pager"] = new PagerModel(itemsCount, ItemsPerPage);
			ViewData.Model = logs
				.OrderByDescending(l => l.Date)
				.Skip(pageIndex * ItemsPerPage)
				.Take(ItemsPerPage)
				.ToList();
			return View();
		}

		/// <summary>
		/// Returns PageResult which renders view with detailed info about log entry
		/// </summary>
		/// <param name="id">Log entry Id.</param>
		[UrlRoute("{id}", false)]
		[UrlRouteConstraint("id", Constraints.IsInt)]
		public ActionResult Item(int id)
		{
			// find log entry
			Log log = Data.Logs.GetLogs().FirstOrDefault(l => l.Id == id);
			if (log == null)
				return HttpNotFound();
			ViewData.Model = log;
			Title.Add("Лог №" + log.Id);

			// set return url
			NameValueCollection qs = (Session["Log.Qs"] as NameValueCollection) ?? new NameValueCollection();
			ViewData["ReturnUrl"] = Url.Action("Index", new { page = Session["Log.Page"] ?? 1 }) + qs.ToHtmlGet();
			return View();
		}

		/// <summary>
		/// Deletes Log entry from database.
		/// </summary>
		/// <param name="id">Log entry Id.</param>
		[UrlRoute("{id}/Delete", false)]
		[UrlRouteConstraint("id", Constraints.IsInt)]
		public ActionResult Delete(int id)
		{
			// find entry
			Log log = Data.Logs.GetLogs().FirstOrDefault(l => l.Id == id);
			if (log == null)
				return HttpNotFound();

			// delete entry from db
			Data.Logs.DeleteLog(log);
			Data.SubmitChanges();
			return RedirectToAction("Index", new { page = Session["Log.Page"] ?? 1 });
		}

		/// <summary>
		/// Removes filtered entries.
		/// </summary>
		/// <param name="startDate">Low bound Date.</param>
		/// <param name="endDate">High bound Date.</param>
		/// <param name="text">Text for search.</param>
		public ActionResult RemoveFiltered(string startDate, string endDate, string text)
		{
			// get all logs
			IQueryable<Log> logs = Data.Logs.GetLogs();

			// filter by startDate
			DateTime filterStartDate = DateTime.UtcNow;
			if (!string.IsNullOrEmpty(startDate))
			{
				if (!DateTime.TryParse(startDate, out filterStartDate))
					ModelState.AddModelError("StartDate", "Введите корректную дату начала");
				else
					logs = logs.Where(l => l.Date >= filterStartDate);
			}

			// filter by endDate
			DateTime filterEndDate = DateTime.UtcNow;
			if (!string.IsNullOrEmpty(endDate))
			{
				if (!DateTime.TryParse(endDate, out filterEndDate))
					ModelState.AddModelError("EndDate", "Введите корректную дату окончания");
				else
					logs = logs.Where(l => l.Date < filterEndDate);
			}

			// filter by containing text
			if (!string.IsNullOrEmpty(text))
			{
				logs = logs.Where(l => l.ShortText.ToLower().Contains(text.ToLower()) ||
										l.Description.ToLower().Contains(text.ToLower()));
			}

			// filter by LogType
			List<byte> types = new List<byte>();
			foreach (string key in this.Request.Params)
			{
				if (key.Length > 0 && key[0] == 'T')
				{
					byte num;
					if (byte.TryParse(key.Substring(1), out num))
						types.Add(num);
				}

			}
			if (types.Count > 0)
				logs = logs.Where(l => types.Contains(l.Type.Id));

			// delete logs
			foreach (Log log in logs)
				Data.Logs.DeleteLog(log);
			Data.SubmitChanges();
			return RedirectToAction("Index");
		}

		/// <summary>
		/// Deletes all logs from database.
		/// </summary>
		public ActionResult DeleteAll()
		{
			// delete logs
			Data.Logs.ClearLogs();
			Data.SubmitChanges();
			return Message("Все логи были удалены.", Url.Action("Index"));
		}
	}
}
